home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / netprog.zip / NETPROG.TAR / rlogin / rcmd.c < prev    next >
C/C++ Source or Header  |  1989-12-17  |  7KB  |  256 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #if defined(LIBC_SCCS) && !defined(lint)
  19. static char sccsid[] = "@(#)rcmd.c    5.20 (Berkeley) 1/24/89";
  20. #endif /* LIBC_SCCS and not lint */
  21.  
  22. #include    <sys/types.h>
  23. #include    <sys/socket.h>
  24. #include    <sys/file.h>
  25. #include    <sys/signal.h>
  26. #include    <netinet/in.h>
  27. #include    <arpa/inet.h>
  28.  
  29. #include    <stdio.h>
  30. #include    <netdb.h>
  31. #include    <errno.h>
  32. extern int    errno;
  33.  
  34. int                    /* return socket descriptor - sockfd1 */
  35. rcmd(ahost, rport, cliuname, servuname, cmd, fd2ptr)
  36. char    **ahost;    /* pointer to address of host name */
  37. u_short    rport;        /* port on server to connect to - network byte order */
  38. char    *cliuname;    /* username on client system (i.e., caller's username */
  39. char    *servuname;    /* username to use on server system */
  40. char    *cmd;        /* command string to execute on server */
  41. int    *fd2ptr;    /* ptr to secondary socket descriptor (if not NULL) */
  42. {
  43.     int            sockfd1, timo, lport;
  44.     long            oldmask;
  45.     char            c;
  46.     struct sockaddr_in    serv_addr, serv2_addr;
  47.     struct hostent        *hp;
  48.     fd_set            readfds;
  49.  
  50.     if ( (hp = gethostbyname(*ahost)) == NULL) {
  51.         herror(*ahost);
  52.         return(-1);
  53.     }
  54.     *ahost = hp->h_name;    /* return hostname we're using to caller */
  55.  
  56.     oldmask = sigblock(sigmask(SIGURG));
  57.  
  58.     lport = IPPORT_RESERVED - 1;
  59.     timo  = 1;
  60.     for ( ; ; ) {
  61.         if ( (sockfd1 = rresvport(&lport)) < 0) {
  62.             if (errno == EAGAIN)
  63.                 fprintf(stderr, "socket: All ports in use\n");
  64.             else
  65.                 perror("rcmd: socket");
  66.             sigsetmask(oldmask);
  67.             return(-1);
  68.         }
  69.  
  70.         fcntl(sockfd1, F_SETOWN, getpid());
  71.                     /* set pid for socket signals */
  72.  
  73.         /*
  74.          * Fill in the socket address of the server, and connect to
  75.          * the server.
  76.          */
  77.  
  78.         bzero((char *) &serv_addr, sizeof(serv_addr));
  79.         serv_addr.sin_family = hp->h_addrtype;
  80.         bcopy(hp->h_addr_list[0], (caddr_t)&serv_addr.sin_addr,
  81.                             hp->h_length);
  82.         serv_addr.sin_port = rport;
  83.         if (connect(sockfd1, (struct sockaddr *) &serv_addr,
  84.                         sizeof(serv_addr)) >= 0)
  85.             break;        /* OK, continue onward */
  86.  
  87.         close(sockfd1);
  88.         if (errno == EADDRINUSE) {
  89.             /*
  90.              * We were able to bind the local address, but couldn't
  91.              * connect to the server.  Decrement the starting
  92.              * port number for rresvport() and try again.
  93.              */
  94.  
  95.             lport--;
  96.             continue;
  97.         }
  98.  
  99.         if (errno == ECONNREFUSED && timo <= 16) {
  100.             /*
  101.              * The connection was refused.  The server's system
  102.              * is probably overloaded.  Sleep for a while, then
  103.              * try again.  We try this 5 times (total of 31 sec).
  104.              */
  105.  
  106.             sleep(timo);
  107.             timo *= 2;    /* increase timer: 1, 2, 4, 8, 16 sec */
  108.             continue;
  109.         }
  110.  
  111.         if (hp->h_addr_list[1] != NULL) {
  112.             /*
  113.              * If there's another address for the host, try it.
  114.              */
  115.  
  116.             int    oerrno;
  117.  
  118.             oerrno = errno;    /* save errno over call to fprintf */
  119.             fprintf(stderr, "connect to address %s: ",
  120.                         inet_ntoa(serv_addr.sin_addr));
  121.             errno = oerrno;
  122.             perror((char *) 0);
  123.  
  124.             hp->h_addr_list++;    /* incr. pointer for next time */
  125.             bcopy(hp->h_addr_list[0], (caddr_t) &serv_addr.sin_addr,
  126.                         hp->h_length);
  127.             fprintf(stderr, "Trying %s...\n",
  128.                         inet_ntoa(serv_addr.sin_addr));
  129.             continue;
  130.         }
  131.  
  132.         perror(hp->h_name);    /* none of the above, quit */
  133.         sigsetmask(oldmask);
  134.         return(-1);
  135.     }
  136.  
  137.     if (fd2ptr == (int *) 0) {
  138.         /*
  139.          * Caller doesn't want a secondary channel.  Write a byte
  140.          * of 0 to the socket, to let the server know this.
  141.          */
  142.  
  143.         write(sockfd1, "", 1);
  144.         lport = 0;
  145.  
  146.     } else {
  147.         /*
  148.          * Create the secondary socket and connect it to the
  149.          * server also.  We have to bind the secondary socket to
  150.          * a reserved TCP port also.
  151.          */
  152.  
  153.         char    num[8];
  154.         int    socktemp, sockfd2, len;
  155.  
  156.         lport--;    /* decrement for starting port# */
  157.         if ( (socktemp = rresvport(&lport)) < 0)
  158.             goto bad;
  159.  
  160.         listen(socktemp, 1);
  161.  
  162.         /*
  163.          * Write an ASCII string with the port number to the server,
  164.          * so it knows which port to connect to.
  165.          */
  166.  
  167.         sprintf(num, "%d", lport);
  168.         if (write(sockfd1, num, strlen(num)+1) != strlen(num)+1) {
  169.             perror("write: setting up stderr");
  170.             close(socktemp);
  171.             goto bad;
  172.         }
  173.  
  174.         FD_ZERO(&readfds);
  175.         FD_SET(sockfd1, &readfds);
  176.         FD_SET(socktemp, &readfds);
  177.         errno = 0;
  178.         if ((select(32, &readfds, (fd_set *) 0, (fd_set *) 0,
  179.                         (struct timeval *) 0) < 1) ||
  180.             !FD_ISSET(socktemp, &readfds)) {
  181.             if (errno != 0)
  182.                 perror("select: setting up stderr");
  183.             else
  184.                 fprintf(stderr,
  185.                 "select: protocol failure in circuit setup.\n");
  186.             close(socktemp);
  187.             goto bad;
  188.         }
  189.  
  190.         /*
  191.          * The server does the connect() to us on the secondary socket.
  192.          */
  193.  
  194.         len = sizeof(serv2_addr);
  195.         sockfd2 = accept(socktemp, &serv2_addr, &len);
  196.         close(socktemp);    /* done with this descriptor */
  197.         if (sockfd2 < 0) {
  198.             perror("accept");
  199.             lport = 0;
  200.             goto bad;
  201.         }
  202.         *fd2ptr = sockfd2;    /* to return to caller */
  203.  
  204.         /*
  205.          * The server has to bind its end of this connection to a
  206.          * reserved port also, or we don't accept it.
  207.          */
  208.  
  209.         serv2_addr.sin_port = ntohs((u_short) serv2_addr.sin_port);
  210.         if ((serv2_addr.sin_family != AF_INET) ||
  211.             (serv2_addr.sin_port >= IPPORT_RESERVED) ||
  212.             (serv2_addr.sin_port <  IPPORT_RESERVED/2)) {
  213.             fprintf(stderr,
  214.                 "socket: protocol failure in circuit setup.\n");
  215.             goto bad2;
  216.         }
  217.     }
  218.  
  219.     write(sockfd1, cliuname, strlen(cliuname)+1);
  220.     write(sockfd1, servuname, strlen(servuname)+1);
  221.     write(sockfd1, cmd, strlen(cmd)+1);
  222.  
  223.     if (read(sockfd1, &c, 1) != 1) {    /* read one byte from server */
  224.         perror(*ahost);
  225.         goto bad2;
  226.     }
  227.  
  228.     if (c != 0) {
  229.         /*
  230.          * We didn't get back the byte of zero.  There was an error
  231.          * detected by the server.  Read everything else on the
  232.          * socket up through a newline, which is an error message from
  233.          * the server, and copy to stderr.
  234.          */
  235.  
  236.         while (read(sockfd1, &c, 1) == 1) {
  237.             write(2, &c, 1);
  238.             if (c == '\n')
  239.                 break;
  240.         }
  241.         goto bad2;
  242.     }
  243.  
  244.     sigsetmask(oldmask);
  245.     return(sockfd1);    /* all OK, return socket descriptor */
  246.  
  247. bad2:
  248.     if (lport)
  249.         close(*fd2ptr);
  250.     /* then fall through */
  251. bad:
  252.     close(sockfd1);
  253.     sigsetmask(oldmask);
  254.     return(-1);
  255. }
  256.